
import java.util.List;



/*
 * 
 */
public interface Board 
{
	
	public static final int BOARD_WALL = 0x23;
	public static final int BOARD_PLAYER = 0x40;
	public static final int BOARD_PLAYER_ON_GOAL_SQUARE = 0x2b;
	public static final int BOARD_BOX = 0x24;
	public static final int BOARD_BOX_ON_GOAL = 0x2a;
	public static final int BOARD_GOAL_SQUARE = 0x2e;
	public static final int BOARD_EMPTY_FLOOR = 0x20;
	
	public static enum CellType
	{
		Wall 				(BOARD_WALL),
		Player 				(BOARD_PLAYER),
		PlayerOnGoalSquare	(BOARD_PLAYER_ON_GOAL_SQUARE),
		Box					(BOARD_BOX),
		BoxOnGoal			(BOARD_BOX_ON_GOAL),
		GoalSquare			(BOARD_GOAL_SQUARE),
		EmptyFloor			(BOARD_EMPTY_FLOOR);
		
		int hexCode;
		
		CellType( int hexCode )
		{
			this.hexCode = hexCode;
		}
		
		public int getHexCode()
		{
			return hexCode;
		}
		
		public boolean isPlayer()
		{
			switch ( this ) 
			{
			
			  case Player: 				return true;
			  case PlayerOnGoalSquare:	return true;

			  default: return false;
			}
		}
		
		public boolean isBox()
		{
			switch ( this ) 
			{
			
			  case Box: 				return true;
			  case BoxOnGoal:			return true;

			  default: return false;
			}
		}
		
		public boolean isGoal()
		{
			switch ( this ) 
			{
			
			  case GoalSquare: 				return true;
			  case PlayerOnGoalSquare:		return true;
			  case BoxOnGoal:				return true;

			  default: return false;
			}
		}
		
		public boolean isWall()
		{
			switch ( this ) 
			{
			
			  case Wall: 				return true;

			  default: return false;
			}
		}
		
		@Override
		public String toString()
		{
			switch ( hexCode ) 
			{
			
			  case BOARD_WALL: 					return "#";
			  case BOARD_PLAYER: 				return "@";
			  case BOARD_PLAYER_ON_GOAL_SQUARE:	return "+";
			  case BOARD_BOX: 					return "$";
			  case BOARD_BOX_ON_GOAL: 			return "*";
			  case BOARD_GOAL_SQUARE: 			return ".";
			  case BOARD_EMPTY_FLOOR: 			return " ";

			  default: throw new RuntimeException();
			}
		}
		
		public char toChar()
		{
			switch ( hexCode ) 
			{
			
			  case BOARD_WALL: 					return '#';
			  case BOARD_PLAYER: 				return '@';
			  case BOARD_PLAYER_ON_GOAL_SQUARE:	return '+';
			  case BOARD_BOX: 					return '$';
			  case BOARD_BOX_ON_GOAL: 			return '*';
			  case BOARD_GOAL_SQUARE: 			return '.';
			  case BOARD_EMPTY_FLOOR: 			return ' ';

			  default: throw new RuntimeException();
			}
		}
		
		public static CellType create( int hexCode )
		{
			switch ( hexCode ) 
			{
			
			  case BOARD_WALL: 					return Wall;
			  case BOARD_PLAYER: 				return Player;
			  case BOARD_PLAYER_ON_GOAL_SQUARE:	return PlayerOnGoalSquare;
			  case BOARD_BOX: 					return Box;
			  case BOARD_BOX_ON_GOAL: 			return BoxOnGoal;
			  case BOARD_GOAL_SQUARE: 			return GoalSquare;
			  case BOARD_EMPTY_FLOOR: 			return EmptyFloor;

			  default: throw new RuntimeException();
			}
		}
	}

	/**
	 * Givet nuvarande braedet och  haemtas alla giltiga drag och returneras i en lista.
	 * 
	 * @param currentPosition Det nuvarande draget varifraan alla nya giltiga drag ska beraeknas.
	 * @param moveRule Regeln som bedaomer om ett visst nytt drag aer giltigt eller ej.
	 * @return en lista med alla giltiga drag.
	 */
	public List<Move> getLegalMoves( Cord currentPosition, MoveRule moveRule );
	
	/**
	 * 
	 * Haemtar celltypen i braedet givet koordinaterna i ett drag.
	 * 
	 * @param move draget i ett Move-objekt
	 * @return celltypen i koordinaterna draget har.
	 * 
	 * @throws IllegalArgumentException om koordinaten aer utanfaor braedet
	 */
	public CellType getCellType( Cord cord );
	
	/**
	 * Haemtar celltypen i braedet givet x och y.
	 * 
	 * @param x X-koordinaten.
	 * @param y Y-koordinaten.
	 * @return celltypen i braedet vid givna koordinater.
	 * 
	 * @throws IllegalArgumentException om koordinaten aer utanfaor braedet
	 */
	public CellType getCellType( int x, int y );
	
//	/**
//	 * Haemtar ett move givet existerande move i given riktning.
//	 * Obs* Det nya draget kan vara ogiltigt faor din anvaendning.
//	 * 
//	 * @param move Det existerande draget.
//	 * @param direction Riktningen det nya draget ska tas ifraan.
//	 * @return det nya draget i ett Move-objekt.
//	 */
//	public Move getAdjacentMoveInDirection( Move cord, Move.Direction direction );
	

	/**
	 * Instances a VisitedCellHelper from this board.
	 */
	public VisitedCellHelper getVisitedBoardHelper();
	
	public boolean[][] getDeadlockArray();
	
	/**
	 * 
	 * @return A list with coordinates of all boxes.
	 */
	public Cord[] getBoxes();
	
	/**
	 * 
	 * @return A list with coordinates of all goals.
	 */
	public Cord[] getGoals();
	
	/**
	 * 
	 */
	public boolean isFinished();
	
	/**
	 * 
	 * @return Coordinates of the player.
	 */
	public Cord getPlayer();
	
	/**
	 * 
	 * @param direction riktningen spelaren ska flyttas.
	 * @return true if move is legal, false otherwise.
	 */
	public int doMovePlayer( Move.Direction direction );
	
	/**
	 * Skriver ut braedet till konsollen.
	 */
	public void printBoard();
	
	/**
	 * @return En klon av braedet
	 */
	public Board clone();
	
	/**
	 * Kollar om ett drag ligger innanfaor braedet
	 * 
	 * @param move draget i fraaga
	 * @return true om det gaor det, annars false.
	 */
	public boolean existsCellAt( Cord cord );
	
	/**
	 * Kollar om tvaa koordinater finns innanfaor braedet
	 * 
	 * @param x X-koordinaten
	 * @param y Y-koordinaten
	 * @return true om dom gaor det, annars false.
	 */
	public boolean existsCellAt( int x, int y );
	
		
}
